package net.droiding.activity;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import net.droiding.R;
import net.droiding.app.Droiding;
import net.droiding.data.Station;
import net.droiding.service.DroidingService;
import net.droiding.utils.map.AvailabilityOverlay;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

public class DroidingActivity extends MapActivity {

	private static final int MENU_SEARCH = 1000;
	private static final int MENU_SETTINGS = 1010;	

	
	private DroidingService droidingService = null;
	
	private ProgressDialog dlgProgress = null;
	
	private MapView map = null;
	private MapController mapController = null;
	private List<Overlay> mapOverlays = null;
	private AvailabilityOverlay highOverlay = null;
	private AvailabilityOverlay mediumOverlay = null;
	private AvailabilityOverlay lowOverlay = null;
	private AvailabilityOverlay noOverlay = null;
	
	private boolean started = false;
	
	private Droiding droiding = null;
	
	static final private int REQ_REGISTER = 0;
	static final private int REQ_CHOOSEPROVIDER = 1;

	private ServiceConnection conn = new ServiceConnection() {
	        public void onServiceConnected(ComponentName className, IBinder service) {
	        	droidingService = ((DroidingService.DroidingBinder)service).getService();
	        }
	        public void onServiceDisconnected(ComponentName className) {
	        	droidingService = null;
	        }
	    };
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        map = (MapView) findViewById(R.id.mapview);
        map.setClickable(true);
        mapController = map.getController();
        mapOverlays = map.getOverlays();
       
        highOverlay = new AvailabilityOverlay(DroidingActivity.this,this.getResources().getDrawable(R.drawable.high_availability));
        mediumOverlay = new AvailabilityOverlay(DroidingActivity.this,this.getResources().getDrawable(R.drawable.medium_availability));
        lowOverlay = new AvailabilityOverlay(DroidingActivity.this,this.getResources().getDrawable(R.drawable.low_availability));
        noOverlay = new AvailabilityOverlay(DroidingActivity.this,this.getResources().getDrawable(R.drawable.no_availability));
       
    	mapOverlays.add(highOverlay);
        mapOverlays.add(mediumOverlay);
        mapOverlays.add(lowOverlay);
        mapOverlays.add(noOverlay);
	        
        droiding = Droiding.getInstance(this);
        
        
        centerOnNapoli();
        
        map.setBuiltInZoomControls(true);
       
//        bindService(new Intent(DroidingActivity.this, 
//	    		DroidingService.class), conn, Context.BIND_AUTO_CREATE);
// 
        if (!droiding.hasUserAccount()) {
        	startRegisterActivity();
        	return;
        }
        if (!droiding.hasDefaultProvider()) {
        	startProviderActivity();
        	return;
        } 
     
        initializeMap();
        
	
    }
    private void initializeMap() {
        double lat = Double.parseDouble(droiding.getDefaultProvider().latitude);
        double lng = Double.parseDouble(droiding.getDefaultProvider().longitude);
        GeoPoint center = new GeoPoint(
            (int) (lat * 1E6), 
            (int) (lng * 1E6));
 
        mapController.animateTo(center);
        mapController.setZoom(droiding.getDefaultProvider().zoomLevel);
        map.invalidate();
		if (droiding.hasStations()) {
			
			
		       
	        mapOverlays.remove(highOverlay);
	        mapOverlays.remove(mediumOverlay);
	        mapOverlays.remove(lowOverlay);
	        mapOverlays.remove(noOverlay);

			noOverlay.clear();
			lowOverlay.clear();
			mediumOverlay.clear();
			highOverlay.clear();
			dlgProgress = ProgressDialog.show(DroidingActivity.this, "",
					"Update map. Please wait...", true);
			MapUpdaterThread t = new MapUpdaterThread(droiding.getStations(), hndMapUpdater);
			t.start();

//			Log.d("DroidingActivity", "processed " + droiding.getStations().size() + " stations (" + (System.currentTimeMillis() - startTime )/1000 + " sec)");
		}
       
        
	}
	private void startProviderActivity() {
		startActivityForResult(new Intent(this, ProviderActivity.class), REQ_CHOOSEPROVIDER);
	}
	private void centerOnNapoli() {
        String coordinates[] = {"40.8333333", "14.25"};
        double lat = Double.parseDouble(coordinates[0]);
        double lng = Double.parseDouble(coordinates[1]);
 
        GeoPoint center = new GeoPoint(
            (int) (lat * 1E6), 
            (int) (lng * 1E6));
 

        mapController.animateTo(center);
        mapController.setZoom(13);
        map.invalidate();
    }
    private void startRegisterActivity() {
        Intent i = new Intent(this, RegisterActivity.class);
        startActivityForResult(i, REQ_REGISTER);
        Log.i("Droiding", "start register activity....");
    }
    
	@Override
	protected void onActivityResult(int requestCode, int resultCode,
		Intent data) {
    	if (requestCode == REQ_REGISTER) {
    		if (resultCode == RESULT_CANCELED) {
    			//close app
    			return;
    		}
    		//result ok
    		if (!droiding.hasDefaultProvider()) {
    			startProviderActivity();
    			return;
    		}
    		if (!droiding.hasStations()) {
    			downloadStations();
    			return;
    		}
    		initializeMap();
    		return;
    		
    	}
    	if (requestCode == REQ_CHOOSEPROVIDER) {
    		if (resultCode == RESULT_CANCELED) {
    			//close app
    			return;
    		}
    		if (!droiding.hasStations()) {
    			downloadStations();
    			return;
    		}
    		initializeMap();
    		return;
    		
    	} 	
    }
    

    private void downloadStations() {
    	dlgProgress = ProgressDialog.show(DroidingActivity.this, "",
				"Download stations. Please wait...", true);
    	droiding.downloadStations(hndListStations);
    }
    final Handler hndListStations = new Handler() {
        public void handleMessage(Message msg) {
        	String result = msg.getData().getString("result");
        	if ("ok".equals(result)) {
        		dlgProgress.dismiss();
        		initializeMap();
        		//updateStations();
//                byte[] xml = msg.getData().getByteArray("xml");
//                if (xml != null && xml.length > 0) {
//                	try {
//                		updateStations(DroidingParser.parseStations(xml));
//                		dlgProgress.dismiss();
//                	} catch (Exception e) {
//                		dlgProgress.dismiss();
//                		showErrorDialog(e.getMessage());
//                	}
//                }          		
        		return;
        	}
        	if ("ko".equals(result)) {
        		dlgProgress.dismiss();
        		showErrorDialog(msg.getData().getString("error"));
        		return;
        	}        	
        }
    };
	private void showErrorDialog(String msg) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage(msg).setCancelable(false).setPositiveButton("Retry",
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						dialog.cancel();
						downloadStations();
						//populateList();
					}
				}).setNegativeButton("Cancel",
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						dialog.cancel();
					}
				});
		AlertDialog alert = builder.create();
		alert.show();

	}    
//	private void updateStations(Station[] stations) {
//		droiding.updateStations(stations);
//		initializeMap();
//	}
	private void startBgService() {
        startService(new Intent(DroidingActivity.this,
        		DroidingService.class));	
        this.started = true;
    }
    
	@Override
	protected void onDestroy() {
		super.onDestroy();
//		if (started) {
//			stopService(new Intent(DroidingActivity.this,
//					DroidingService.class));
//			this.started = false;
//		}
//		unbindService(conn);
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(0, MENU_SEARCH, 0, R.string.optmenu_search).setIcon(android.R.drawable.ic_menu_search);
		menu.add(0, MENU_SETTINGS, 0, R.string.optmenu_settings).setIcon(android.R.drawable.ic_menu_preferences);
		return true;	
	}
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
			case MENU_SEARCH:
				startActivity(new Intent(this, FavoriteStationsActivity.class));
				return true;
			case MENU_SETTINGS:
				startActivityForResult(new Intent(this, ProviderActivity.class), REQ_CHOOSEPROVIDER);
			    return true;
		}
		return false;
	}
	
	@Override
	protected boolean isRouteDisplayed() {
		// TODO Auto-generated method stub
		return false;
	}
	
	  // Define the Handler that receives messages from the thread and update the progress
    final Handler hndMapUpdater = new Handler() {
        public void handleMessage(Message msg) {  
        	mapOverlays.add(highOverlay);
            mapOverlays.add(mediumOverlay);
            mapOverlays.add(lowOverlay);
            mapOverlays.add(noOverlay);
   	        map.invalidate();
   	        dlgProgress.dismiss();
        }
    };
	
	private class MapUpdaterThread extends Thread {
		private Station[] stations = null;
		private Handler handler = null;
		public MapUpdaterThread(Station[] stations, Handler handler) {
			this.stations = stations;
			this.handler = handler;
		}
		public void run() {
			Calendar cal = new GregorianCalendar();
			SimpleDateFormat fmt = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
			long startTime = System.currentTimeMillis();
			ArrayList<OverlayItem> high = new ArrayList<OverlayItem>();
			ArrayList<OverlayItem> med = new ArrayList<OverlayItem>();
			ArrayList<OverlayItem> low = new ArrayList<OverlayItem>();
			ArrayList<OverlayItem> no = new ArrayList<OverlayItem>();
			
			for (Station st : stations) {
		        double lat = Double.parseDouble(st.latitude);
		        double lng = Double.parseDouble(st.longitude);
		        cal.setTimeInMillis(st.lastUpdate);
		        StringBuffer sb = new StringBuffer();
		        sb
		        	.append("bikes: ")
		        	.append(st.bikes)
		        	.append("\nslots: ")
		        	.append(st.slots)
		        	.append("\nlast update: ")
		        	.append(fmt.format(cal.getTime()));
		        GeoPoint point = new GeoPoint(
		            (int) (lat * 1E6), 
		            (int) (lng * 1E6));
		        OverlayItem overlayitem = new OverlayItem(point, st.location, sb.toString());
		        if (st.bikes == 0)
		        	no.add(overlayitem);
		        else if (st.bikes > 0 && st.bikes < 3) 
		        	low.add(overlayitem);
		        else if (st.bikes >= 3 && st.bikes < 6)
		        	med.add(overlayitem);
		        else
		        	high.add(overlayitem);
			}
			Log.d("Droiding", "interm:" + (System.currentTimeMillis() - startTime)/1000 + " secs");
			noOverlay.addAll(no);
			lowOverlay.addAll(low);
			mediumOverlay.addAll(med);
			highOverlay.addAll(high);
			
			Log.d("Droiding",  "final:" + (System.currentTimeMillis() - startTime)/1000 + " secs");
			handler.sendEmptyMessage(0);
		}
	}
}